﻿using System;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using GqqMvcWeb;
using Mvc4Learn.Controllers;
using Mvc4Learn.Models;

namespace GqqMvcWeb.Tests.Controllers
{

    [TestClass]
    public class AccountControllerTest
    {

     #region 修改密码测试
//        [TestMethod]
        //        public void ChangePassword_Get_ReturnsView()
        //        {
        //            // Arrange
        //            AccountController controller = GetAccountController();
        //
        //            // Act
        //            ActionResult result = controller.();
        //
        //            // Assert
        //            Assert.IsInstanceOfType(result, typeof(ViewResult));
        //            Assert.AreEqual(10, ((ViewResult)result).ViewData["PasswordLength"]);
        //        }
        //
        //        [TestMethod]
        //        public void ChangePassword_Post_ReturnsRedirectOnSuccess()
        //        {
        //            // Arrange
        //            AccountController controller = GetAccountController();
        //            LocalPasswordModel model = new LocalPasswordModel()
        //            {
        //                OldPassword = "goodOldPassword",
        //                NewPassword = "goodNewPassword",
        //                ConfirmPassword = "goodNewPassword"
        //            };
        //
        //            // Act
        //            ActionResult result = controller.ChangePassword(model);
        //
        //            // Assert
        //            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
        //            RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
        //            Assert.AreEqual("ChangePasswordSuccess", redirectResult.RouteValues["action"]);
        //        }
        //
        //        [TestMethod]
        //        public void ChangePassword_Post_ReturnsViewIfChangePasswordFails()
        //        {
        //            // Arrange
        //            AccountController controller = GetAccountController();
        //            LocalPasswordModel model = new LocalPasswordModel()
        //            {
        //                OldPassword = "goodOldPassword",
        //                NewPassword = "badNewPassword",
        //                ConfirmPassword = "badNewPassword"
        //            };
        //
        //            // Act
        //            ActionResult result = controller.ChangePassword(model);
        //
        //            // Assert
        //            Assert.IsInstanceOfType(result, typeof(ViewResult));
        //            ViewResult viewResult = (ViewResult)result;
        //            Assert.AreEqual(model, viewResult.ViewData.Model);
        //            Assert.AreEqual("The current password is incorrect or the new password is invalid.", controller.ModelState[""].Errors[0].ErrorMessage);
        //            Assert.AreEqual(10, viewResult.ViewData["PasswordLength"]);
        //        }
        //
        //        [TestMethod]
        //        public void ChangePassword_Post_ReturnsViewIfModelStateIsInvalid()
        //        {
        //            // Arrange
        //            AccountController controller = GetAccountController();
        //            LocalPasswordModel model = new LocalPasswordModel()
        //            {
        //                OldPassword = "goodOldPassword",
        //                NewPassword = "goodNewPassword",
        //                ConfirmPassword = "goodNewPassword"
        //            };
        //            controller.ModelState.AddModelError("", "Dummy error message.");
        //
        //            // Act
        //            ActionResult result = controller.ChangePassword(model);
        //
        //            // Assert
        //            Assert.IsInstanceOfType(result, typeof(ViewResult));
        //            ViewResult viewResult = (ViewResult)result;
        //            Assert.AreEqual(model, viewResult.ViewData.Model);
        //            Assert.AreEqual(10, viewResult.ViewData["PasswordLength"]);
        //        }
        //
        //        [TestMethod]
        //        public void ChangePasswordSuccess_ReturnsView()
        //        {
        //            // Arrange
        //            AccountController controller = GetAccountController();
        //
        //            // Act
        //            ActionResult result = controller.ChangePasswordSuccess();
        //
        //            // Assert
        //            Assert.IsInstanceOfType(result, typeof(ViewResult));
        //        }

        #endregion


        [TestMethod]
        public void LogOff_LogsOutAndRedirects()
        {
            // Arrange
            AccountController controller = GetAccountController();

            // Act
            ActionResult result = controller.LogOff();

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
            Assert.AreEqual("Home", redirectResult.RouteValues["controller"]);
            Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
//            Assert.IsTrue(((MockFormsAuthenticationService)controller.FormsService).SignOut_WasCalled);
        }

        [TestMethod]
        public void Login_Get_ReturnsView()
        {
            // Arrange
            AccountController controller = GetAccountController();

            // Act
            ActionResult result = controller.Login("ss");

            // Assert
            Assert.IsInstanceOfType(result, typeof(ViewResult));
        }

        [TestMethod]
        public void Login_Post_ReturnsRedirectOnSuccess_WithoutReturnUrl()
        {
            // Arrange
            AccountController controller = GetAccountController();
            LoginModel model = new LoginModel()
            {
                UserName = "someUser",
                Password = "goodPassword",
                RememberMe = false
            };

            // Act
            ActionResult result = controller.Login(model, null);

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
            Assert.AreEqual("Home", redirectResult.RouteValues["controller"]);
            Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
//            Assert.IsTrue(((MockFormsAuthenticationService)controller).SignIn_WasCalled);
        }

        [TestMethod]
        public void Login_Post_ReturnsRedirectOnSuccess_WithLocalReturnUrl()
        {
            // Arrange
            AccountController controller = GetAccountController();
            LoginModel model = new LoginModel()
            {
                UserName = "someUser",
                Password = "goodPassword",
                RememberMe = false
            };

            // Act
            ActionResult result = controller.Login(model, "/someUrl");

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectResult));
            RedirectResult redirectResult = (RedirectResult)result;
            Assert.AreEqual("/someUrl", redirectResult.Url);
//            Assert.IsTrue(((MockFormsAuthenticationService)controller.FormsService).SignIn_WasCalled);
        }

        [TestMethod]
        public void Login_Post_ReturnsRedirectToHomeOnSuccess_WithExternalReturnUrl()
        {
            // Arrange
            AccountController controller = GetAccountController();
            LoginModel model = new LoginModel()
            {
                UserName = "someUser",
                Password = "goodPassword",
                RememberMe = false
            };

            // Act
            ActionResult result = controller.Login(model, "http://malicious.example.net");

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
            Assert.AreEqual("Home", redirectResult.RouteValues["controller"]);
            Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
//            Assert.IsTrue(((MockFormsAuthenticationService)controller.FormsService).SignIn_WasCalled);
        }

        [TestMethod]
        public void Login_Post_ReturnsViewIfModelStateIsInvalid()
        {
            // Arrange
            AccountController controller = GetAccountController();
            LoginModel model = new LoginModel()
            {
                UserName = "someUser",
                Password = "goodPassword",
                RememberMe = false
            };
            controller.ModelState.AddModelError("", "Dummy error message.");

            // Act
            ActionResult result = controller.Login(model, null);

            // Assert
            Assert.IsInstanceOfType(result, typeof(ViewResult));
            ViewResult viewResult = (ViewResult)result;
            Assert.AreEqual(model, viewResult.ViewData.Model);
        }

        [TestMethod]
        public void Login_Post_ReturnsViewIfValidateUserFails()
        {
            // Arrange
            AccountController controller = GetAccountController();
            LoginModel model = new LoginModel()
            {
                UserName = "someUser",
                Password = "badPassword",
                RememberMe = false
            };

            // Act
            ActionResult result = controller.Login(model, null);

            // Assert
            Assert.IsInstanceOfType(result, typeof(ViewResult));
            ViewResult viewResult = (ViewResult)result;
            Assert.AreEqual(model, viewResult.ViewData.Model);
            Assert.AreEqual("The user name or password provided is incorrect.", controller.ModelState[""].Errors[0].ErrorMessage);
        }

        [TestMethod]
        public void Register_Get_ReturnsView()
        {
            // Arrange
            AccountController controller = GetAccountController();

            // Act
            ActionResult result = controller.Register();

            // Assert
            Assert.IsInstanceOfType(result, typeof(ViewResult));
            Assert.AreEqual(10, ((ViewResult)result).ViewData["PasswordLength"]);
        }

        [TestMethod]
        public void Register_Post_ReturnsRedirectOnSuccess()
        {
            // Arrange
            AccountController controller = GetAccountController();
            RegisterModel model = new RegisterModel()
            {
                UserName = "someUser",
//                Email = "goodEmail",
                Password = "goodPassword",
                ConfirmPassword = "goodPassword"
            };

            // Act
            ActionResult result = controller.Register(model);

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
            Assert.AreEqual("Home", redirectResult.RouteValues["controller"]);
            Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
        }

        [TestMethod]
        public void Register_Post_ReturnsViewIfRegistrationFails()
        {
            // Arrange
            AccountController controller = GetAccountController();
            RegisterModel model = new RegisterModel()
            {
                UserName = "duplicateUser",
//                Email = "goodEmail",
                Password = "goodPassword",
                ConfirmPassword = "goodPassword"
            };

            // Act
            ActionResult result = controller.Register(model);

            // Assert
            Assert.IsInstanceOfType(result, typeof(ViewResult));
            ViewResult viewResult = (ViewResult)result;
            Assert.AreEqual(model, viewResult.ViewData.Model);
            Assert.AreEqual("Username already exists. Please enter a different user name.", controller.ModelState[""].Errors[0].ErrorMessage);
            Assert.AreEqual(10, viewResult.ViewData["PasswordLength"]);
        }

        [TestMethod]
        public void Register_Post_ReturnsViewIfModelStateIsInvalid()
        {
            // Arrange
            AccountController controller = GetAccountController();
            RegisterModel model = new RegisterModel()
            {
                UserName = "someUser",
//                Email = "goodEmail",
                Password = "goodPassword",
                ConfirmPassword = "goodPassword"
            };
            controller.ModelState.AddModelError("", "Dummy error message.");

            // Act
            ActionResult result = controller.Register(model);

            // Assert
            Assert.IsInstanceOfType(result, typeof(ViewResult));
            ViewResult viewResult = (ViewResult)result;
            Assert.AreEqual(model, viewResult.ViewData.Model);
            Assert.AreEqual(10, viewResult.ViewData["PasswordLength"]);
        }

        private static AccountController GetAccountController()
        {
            RequestContext requestContext = new RequestContext(new MockHttpContext(), new RouteData());
            AccountController controller = new AccountController()
            {
//                FormsService = new MockFormsAuthenticationService(),
//                MembershipService = new MockMembershipService(),
                Url = new UrlHelper(requestContext),
            };
            controller.ControllerContext = new ControllerContext()
            {
                Controller = controller,
                RequestContext = requestContext
            };
            return controller;
        }
/*
        private class MockFormsAuthenticationService : IFormsAuthenticationService
        {
            public bool SignIn_WasCalled;
            public bool SignOut_WasCalled;

            public void SignIn(string userName, bool createPersistentCookie)
            {
                // verify that the arguments are what we expected
                Assert.AreEqual("someUser", userName);
                Assert.IsFalse(createPersistentCookie);

                SignIn_WasCalled = true;
            }

            public void SignOut()
            {
                SignOut_WasCalled = true;
            }
       } */

        private class MockHttpContext : HttpContextBase
        {
            private readonly IPrincipal _user = new GenericPrincipal(new GenericIdentity("someUser"), null /* roles */);
            private readonly HttpRequestBase _request = new MockHttpRequest();

            public override IPrincipal User
            {
                get
                {
                    return _user;
                }
                set
                {
                    base.User = value;
                }
            }

            public override HttpRequestBase Request
            {
                get
                {
                    return _request;
                }
            }
        }

        private class MockHttpRequest : HttpRequestBase
        {
            private readonly Uri _url = new Uri("http://mysite.example.com/");

            public override Uri Url
            {
                get
                {
                    return _url;
                }
            }
        }

//        private class MockMembershipService : IMembershipService
//        {
//            public int MinPasswordLength
//            {
//                get { return 10; }
//            }
//
//            public bool ValidateUser(string userName, string password)
//            {
//                return (userName == "someUser" && password == "goodPassword");
//            }
//
//            public MembershipCreateStatus CreateUser(string userName, string password, string email)
//            {
//                if (userName == "duplicateUser")
//                {
//                    return MembershipCreateStatus.DuplicateUserName;
//                }
//
//                // verify that values are what we expected
//                Assert.AreEqual("goodPassword", password);
//                Assert.AreEqual("goodEmail", email);
//
//                return MembershipCreateStatus.Success;
//            }
//
//            public bool ChangePassword(string userName, string oldPassword, string newPassword)
//            {
//                return (userName == "someUser" && oldPassword == "goodOldPassword" && newPassword == "goodNewPassword");
//            }
//        }

    }
}
